package com.andaily.service.impl;

import com.andaily.domain.dto.log.*;
import com.andaily.domain.log.Log;
import com.andaily.domain.log.LogComment;
import com.andaily.domain.log.LogRepository;
import com.andaily.domain.log.LogType;
import com.andaily.domain.shared.paginated.PaginatedLoader;
import com.andaily.domain.shared.security.SecurityUtils;
import com.andaily.domain.user.LogSetting;
import com.andaily.domain.user.User;
import com.andaily.domain.user.UserSetting;
import com.andaily.infrastructure.support.LogHelper;
import com.andaily.service.LogService;
import com.andaily.service.UserService;
import org.apache.commons.lang.StringUtils;
import org.springframework.beans.factory.annotation.Autowired;

import java.util.List;
import java.util.Map;

/**
 * @author Shengzhao Li
 */
public class LogServiceImpl implements LogService {

    private static LogHelper logger = LogHelper.create(LogServiceImpl.class);

    @Autowired
    private LogRepository logRepository;
    @Autowired
    private UserService userService;

    @Override
    public LogDto loadLogDto(String guid) {
        LogDto logDto = new LogDto();
        if (StringUtils.isNotEmpty(guid)) {
            Log log = logRepository.findByGuid(guid);
            logDto = new LogDto(log);
        }
        Boolean allowRecordPosition = logRepository.findAllowRecordPosition(SecurityUtils.currentUserGuid());
        logDto.setAllowRecordPosition(allowRecordPosition);
        return logDto;
    }

    @Override
    public List<LogTypeDto> loadAvailableLogTypes() {
        String userGuid = SecurityUtils.currentUserGuid();
        List<LogType> logTypes = logRepository.findAvailableLogTypes(userGuid);
        return LogTypeDto.toDtos(logTypes);
    }

    @Override
    public void persistLogDto(LogDto logDto) {
        Log log = logDto.instance();
        log.update(logDto);
        log.updateOwner(userService.currentUser());

        if (logDto.isNewly()) {
            logRepository.saveLog(log);
        } else {
            logger.debug("Update Log: " + log);
            logRepository.updateLog(log);
        }
    }

    @Override
    public LogOverviewDto loadLogOverview(LogOverviewDto overviewDto) {
        final Map<String, Object> params = overviewDto.params();
        return overviewDto.load(new PaginatedLoader<LogDto>() {
            @Override
            public List<LogDto> loadList() {
                List<Log> logs = logRepository.findLogs(params);
                return LogDto.toDtos(logs);
            }

            @Override
            public int loadTotalSize() {
                return logRepository.totalLogs(params);
            }
        });
    }

    @Override
    public LogDetailsDto loadLogDetails(String guid) {
        final Log log = logRepository.findByGuid(guid);
        return new LogDetailsDto(log);
    }

    @Override
    public int loadTotalLog() {
        return logRepository.totalAvailableLogs();
    }

    @Override
    public LogTypeOverviewDto loadLogTypeOverview(LogTypeOverviewDto overviewDto) {
        final Map<String, Object> params = overviewDto.params();
        return overviewDto.load(new PaginatedLoader<LogTypeDto>() {
            @Override
            public List<LogTypeDto> loadList() {
                List<LogType> logTypes = logRepository.findLogTypes(params);
                return LogTypeDto.toDtos(logTypes);
            }

            @Override
            public int loadTotalSize() {
                return logRepository.totalLogTypes(params);
            }
        });
    }

    @Override
    public LogTypeDto loadLogTypeDetails(String guid) {
        LogType logType = logRepository.findLogTypeByGuid(guid);
        LogTypeDto logTypeDto = new LogTypeDto(logType);

        int amount = logRepository.countOfLogType(guid);
        logTypeDto.setLogAmount(amount);
        return logTypeDto;
    }

    @Override
    public LogTypeDto loadLogType(String guid) {
        LogTypeDto logTypeDto = new LogTypeDto();
        if (StringUtils.isNotEmpty(guid)) {
            logTypeDto = new LogTypeDto(logRepository.findLogTypeByGuid(guid));
        }
        return logTypeDto;
    }

    @Override
    public void persistLogTypeDto(LogTypeDto logTypeDto) {
        LogType logType;
        if (logTypeDto.isNewly()) {
            logType = logTypeDto.instance();
            logType.updateCreator(userService.currentUser());
            logRepository.saveLogType(logType);
        } else {
            logType = logRepository.findLogTypeByGuid(logTypeDto.getGuid());
            logType.update(logTypeDto.getName(), logTypeDto.getDescription());
            logRepository.updateLogType(logType);
        }
    }

    @Override
    public void deleteLogType(String guid) {
        logRepository.archiveLogType(guid, true);
    }

    @Override
    public void archiveLog(String guid) {
        logRepository.archiveLog(guid, true);
    }

    @Override
    public LogCommentDto loadLogCommentDto(String guid, String logGuid) {
        LogCommentDto logCommentDto = new LogCommentDto(logGuid);
        if (StringUtils.isNotEmpty(guid)) {
            LogComment logComment = logRepository.findLogCommentByGuid(guid);
            logCommentDto = new LogCommentDto(logComment);
        }
        return logCommentDto;
    }

    @Override
    public void persistLogComment(LogCommentDto logCommentDto) {
        final User user = userService.currentUser();
        final Log log = logRepository.findByGuid(logCommentDto.getLogGuid());
        LogComment logComment = new LogComment(user, log, logCommentDto.getContent());
        logRepository.saveLogComment(logComment);
    }

    @Override
    public LogCommentDto loadLogCommentDto(String guid) {
        LogComment logComment = logRepository.findLogCommentByGuid(guid);
        return new LogCommentDto(logComment);
    }

    @Override
    public void archiveLogComment(String guid) {
        logRepository.archiveLogComment(guid, true);
    }

    @Override
    public LogSettingDto loadLogSettingDto() {
        final LogSetting logSetting = findUserSetting().logSetting();
        return (logSetting != null ? new LogSettingDto(logSetting) : new LogSettingDto());
    }

    private UserSetting findUserSetting() {
        String userGuid = SecurityUtils.currentUserGuid();
        return userService.loadUserSettingByUserGuid(userGuid);
    }

    @Override
    public void updateLogSetting(LogSettingDto logSettingDto) {
        final UserSetting userSetting = findUserSetting();
        logRepository.updateLogSetting(logSettingDto.isAllowRecordPosition(), userSetting.guid());
    }

    @Override
    public void setDefaultLogType(String guid) {
        String userGuid = SecurityUtils.currentUserGuid();
        logRepository.cancelAllSelectedTypes(userGuid);
        logRepository.updateSelectLogType(userGuid, guid);
    }


}
